package com.mrdeer.iot.handler;

import com.mrdeer.iot.bean.ChannelInfo;
import com.mrdeer.iot.bean.command.DeviceStatus;
import com.mrdeer.iot.bean.command.Protocol;
import com.mrdeer.iot.bean.enums.EMQExchange;
import com.mrdeer.iot.constant.DriverContext;
import com.mrdeer.iot.constant.FrameConst;
import com.mrdeer.iot.entity.DeviceEntity;
import com.mrdeer.iot.processor.IDataProcessor;
import com.mrdeer.iot.processor.impl.ControlProcessor;
import com.mrdeer.iot.processor.impl.HeartBeatProcessor;
import com.mrdeer.iot.processor.impl.InvalidProcessor;
import com.mrdeer.iot.processor.impl.StatusProcessor;
import com.mrdeer.iot.service.DeviceService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * RTU 设备 解码
 *
 * @Author: xie jianchu
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class ProcessorHandler extends ChannelInboundHandlerAdapter {

    @Resource
    private DeviceService deviceService;

    @Resource
    private SimpMessagingTemplate messagingTemplate;

    private final IDataProcessor controlProcessor = new ControlProcessor();
    private final IDataProcessor statusProcessor = new StatusProcessor();
    private final IDataProcessor heartBeatProcessor = new HeartBeatProcessor();
    private final IDataProcessor invalidProcessor = new InvalidProcessor();

    public ProcessorHandler() {
        controlProcessor.setNextProcessor(statusProcessor);
        statusProcessor.setNextProcessor(invalidProcessor);
        invalidProcessor.setNextProcessor(heartBeatProcessor);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof Protocol) {
            ChannelInfo channelInfo = DriverContext.CHANNEL_INFO_MAP.get(ctx.channel().id());
            Protocol protocol = (Protocol) msg;
            DeviceStatus deviceStatus = new DeviceStatus(protocol.getData());
            if (protocol.getType().equals(FrameConst.heartbeat)) {
                messagingTemplate.convertAndSendToUser(protocol.getDest(), "/queue/subscribe", deviceStatus);   //实时的向前端发送设备当前状态
                DeviceEntity deviceEntity = deviceService.selectDeviceByAddress(protocol.getDest());
                if (deviceEntity != null) {
                    deviceEntity.setName(ctx.channel().id().asShortText());
                    deviceEntity.setMac(ctx.channel().id().asShortText());
                    deviceEntity.setAddress(protocol.getDest());
                    deviceEntity.setStatus(1);
                    deviceEntity.setCommand(protocol.getData());
                    deviceService.update(deviceEntity);
                } else {
                    deviceEntity = new DeviceEntity(channelInfo.getChannelId().asShortText(), channelInfo.getChannelId().asShortText(), protocol.getDest(), "0", "0", "0", "0", "1.0.0", "", 0, 1);
                    deviceEntity.setMac(ctx.channel().id().asShortText());
                    deviceEntity.setName(ctx.channel().id().asShortText());
                    deviceService.addDevice(deviceEntity);
                }
                controlProcessor.translate(ctx, channelInfo, protocol);
                buildRtuChannelInfo(ctx, channelInfo);
            } else if (protocol.getType().equals(FrameConst.invalid)) {
                //无效命令,故障

            } else if (protocol.getType().equals(FrameConst.status)) {
                //状态帧，是设备对服务器控制指令的应答

            } else {
                controlProcessor.translate(ctx, channelInfo, protocol);
                buildRtuChannelInfo(ctx, channelInfo);
                ctx.fireChannelRead(channelInfo);
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

    private void buildRtuChannelInfo(ChannelHandlerContext ctx, ChannelInfo channelInfo) {
        //如果不存在在物联网信息则使用sn号添加并注册队列标记，否则使用物联网id
        channelInfo.setSn(ctx.channel().id().toString());
        channelInfo.setChannel(ctx.channel());
        ChannelManagerHandler.setRTUChannelInfo(ctx, channelInfo.getProtocol(), channelInfo.getSn());
        if (channelInfo.getProtocol() == null) {
            EMQExchange[] emqExchanges = {EMQExchange.RTU_UNREGISTERED};
            channelInfo.setEmqExchanges(emqExchanges);
        }
    }
}
